package com.demon.activitychange.util;

import android.text.TextUtils;

import com.demon.activitychange.xposed.PayUtils;

import java.io.File;

public class ShellUtils {
    private ShellUtils() {
        /** cannot be instantiated **/
        throw new UnsupportedOperationException("cannot be instantiated");
    }

    public static boolean isRoot() {
        return Shell.execCommand("echo root", true).result == 0;
    }

    public static boolean exists(String file) {
        return Shell.execCommand("ls " + file, true).result == 0;
    }

    public static boolean exists(File file) {
        return Shell.execCommand("ls " + file.getAbsolutePath(), true).result == 0;
    }

    public static void deleteFile(File file) {
        String name = file.getName();
        if (exists(file)) {
            boolean success = Shell.execCommand("rm -fr " + file.getAbsolutePath(), true).result == 0;
            if (success) {
                TraceUtil.d(name + " 文件删除成功！");
            } else {
                TraceUtil.e(name + " 文件删除失败！");
            }
        } else {
            TraceUtil.d(name + " 文件不存在！");
        }
    }

    public static void createDir(File file) {
        String name = file.getName();
        boolean success = Shell.execCommand("mkdir -p " + file.getAbsolutePath(), true).result == 0;
        if (success) {
            TraceUtil.d(name + " 目录创建成功！");
        } else {
            TraceUtil.e(name + " 目录创建失败！");
        }
    }

    public static void copyFile(File file, File dir) {
        String name = file.getName();
        String targetFile = dir.getAbsolutePath() + "/" + name;

        if (exists(file)) {
            TraceUtil.d(name + " 新文件存在！");
        } else {
            TraceUtil.e(name + " 新文件不存在，复制失败！");
            return;
        }

        if (exists(targetFile)) {
            boolean success = Shell.execCommand("rm -fr " + targetFile, true).result == 0;
            if (success) {
                TraceUtil.d(name + " 老文件删除成功！");
            } else {
                TraceUtil.e(name + " 老文件删除失败！");
                return;
            }
        } else {
            TraceUtil.d(name + " 老文件不存在！");
        }

        // 安卓copy文件，需要尽可能保留文件属性（包括所有者、所属组、权限与时间）
        boolean success = Shell.execCommand("cp -pr " + file.getAbsolutePath() + " " + dir.getAbsolutePath(), true).result == 0;
        if (success) {
            TraceUtil.d(name + " 新文件复制成功！");
        } else {
            TraceUtil.e(name + " 新文件复制失败！");
        }
    }

    public static void copyFileAndCtx(File file, File dir) {
        String name = file.getName();
        String targetFile = dir.getAbsolutePath() + "/" + name;

        if (exists(file)) {
            TraceUtil.d(name + " 新文件存在！");
        } else {
            TraceUtil.e(name + " 新文件不存在，复制失败！");
            return;
        }

        if (exists(targetFile)) {
            boolean success = Shell.execCommand("rm -fr " + targetFile, true).result == 0;
            if (success) {
                TraceUtil.d(name + " 老文件删除成功！");
            } else {
                TraceUtil.e(name + " 老文件删除失败！");
                return;
            }
        } else {
            TraceUtil.d(name + " 老文件不存在！");
        }

        // 安卓copy文件，需要尽可能保留文件属性（包括所有者、所属组、权限与时间）
        boolean success = Shell.execCommand("cp -pr " + file.getAbsolutePath() + " " + dir.getAbsolutePath(), true).result == 0;
        if (success) {
            TraceUtil.d(name + " 新文件复制成功！");
        } else {
            TraceUtil.e(name + " 新文件复制失败！");
        }

        // 安卓copy文件，需要保持文件se上下文一致
        String ctx = readSeCtx(file);
        if (!TextUtils.isEmpty(ctx)) {
            if (setSeCtx(dir.getAbsolutePath() + "/" + name, ctx)) {
                TraceUtil.d(name + " ctx设置成功！");
            } else {
                TraceUtil.e(name + " ctx设置失败");
            }
        }
    }

    public static void moveFile(File file, File dir) {
        String name = file.getName();
        String targetFile = dir.getAbsolutePath() + "/" + name;

        if (exists(file)) {
            TraceUtil.d(name + " 新文件存在！");
        } else {
            TraceUtil.e(name + " 新文件不存在，移动失败！");
            return;
        }

        if (exists(targetFile)) {
            boolean success = Shell.execCommand("rm -fr " + targetFile, true).result == 0;
            if (success) {
                TraceUtil.d(name + " 老文件删除成功！");
            } else {
                TraceUtil.e(name + " 老文件删除失败！");
                return;
            }
        } else {
            TraceUtil.d(name + " 老文件不存在！");
        }

        boolean success = Shell.execCommand("mv -f " + file.getAbsolutePath() + " " + dir.getAbsolutePath(), true).result == 0;
        if (success) {
            TraceUtil.d(name + " 新文件移动成功！");
        } else {
            TraceUtil.e(name + " 新文件移动失败！");
        }
    }

    public static boolean isAppRunning(String packageName) {
        return Shell.execCommand("ps | grep " + packageName, false).result == 0;
    }

    public static boolean exitApp(String packageName) {
        return Shell.execCommand("am force-stop " + packageName, true).result == 0;
    }

    public static boolean isSELinux() {
        Shell.CommandResult result = Shell.execCommand("getenforce", true);
        if (result.result == 0) {
            if ("Permissive".equals(result.successMsg)) {
                TraceUtil.e("SELinux is Permissive");
                return false;
            } else if ("Enforcing".equals(result.successMsg)) {
                TraceUtil.e("SELinux is Enforcing");
                return true;
            }
        }
        TraceUtil.e("SELinux is unknown");
        return true;
    }

    public static boolean openSELinux() {
        if (Shell.execCommand("setenforce 1", true).result == 0) {
            if (isSELinux()) {
                return true;
            }
        }
        return false;
    }

    public static boolean closeSELinux() {
        if (Shell.execCommand("setenforce 0", true).result == 0) {
            if (!isSELinux()) {
                return true;
            }
        }
        return false;
    }

    public static String readSeCtx(File file) {
        String name = file.getName();
        Shell.CommandResult result = Shell.execCommand("ls -Z " + file.getAbsolutePath(), true);
        if (result.result == 0) {
            TraceUtil.d(name + " properties: " + result.successMsg);
            String ctx = "u:" + PayUtils.getMidText(result.successMsg, "u:", " ");
            TraceUtil.e(name + " ctx: " + ctx);
            return ctx;
        }
        return null;
    }

    public static boolean setSeCtx(String file, String ctx) {
        return Shell.execCommand("chcon -R " + ctx + " " + file, true).result == 0;
    }

}
